#!/usr/bin/env python
# encoding: utf-8

import os, sys, stat, errno
# pull in some spaghetti to make this stuff work without fuse-py being installed
try:
    import _find_fuse_parts
except ImportError:
    pass
import fuse
from fuse import Fuse

import time
from errno import *
from stat import *
import fcntl
from haokanfs.haokanapi import HaokanAPI
from haokanfs import settings

if not hasattr(fuse, '__version__'):
    raise RuntimeError, \
        "your fuse-py doesn't know of fuse.__version__, probably it's too old."

fuse.fuse_python_api = (0, 2)

# TODO 列出某用户所有故事
# TODO 列出故事下的所有图片
# TODO 显示图片
haokan=HaokanAPI(settings.username)

def flag2mode(flags):
    md = {os.O_RDONLY: 'r', os.O_WRONLY: 'w', os.O_RDWR: 'w+'}
    m = md[flags & (os.O_RDONLY | os.O_WRONLY | os.O_RDWR)]
    if flags | os.O_APPEND:
        m = m.replace('w', 'a', 1)
    return m

class MyStat(fuse.Stat):
    def __init__(self):
        print "=======================MyStat __init__======================="
        self.st_mode = 0
        self.st_ino = 0
        self.st_dev = 0
        self.st_nlink = 0
        self.st_uid = 0
        self.st_gid = 0
        self.st_size = 0
        self.st_atime = 0
        self.st_mtime = 0
        self.st_ctime = 0

class HaokanFS(Fuse):
    
    def getattr(self, path):
        print "=======================HaokanFS getattr",path
        fname = os.path.basename(path)
        st = MyStat()
        if path == '/':
            st.st_mode = stat.S_IFDIR | 0755
            st.st_nlink = 2
        elif path.count('/')>=2:
            st.st_mode = stat.S_IFREG | 0444
            st.st_nlink = 1
            print "===========================set size=============="
            buf=haokan.getImage(fname)
            size=len(open(buf).read())
            print "buf length is",size
            st.st_size = size
        else:
            st.st_mode = stat.S_IFDIR | 0755
            st.st_nlink = 2
        return st

    def readdir(self, path, offset):
        print "=======================readdir======================"
        lst=[]
        for dirlink in '.','..':
            lst.append(dirlink)
        if path == '/':
            for story_id,story_name in haokan.getStorys():
                lst.append(story_name)
                print "story_id",story_id
        else:
            story_name=path.replace("/","")
            if story_name in haokan.storys:
                story_id=haokan.storys[story_name]
                for img in haokan.getPhotos(story_id):
                    lst.append(img)
        for r in lst:
            yield fuse.Direntry(r)

    # def open(self, path, flags):
    #     print "=======================open======================="
    #     #return -errno.ENOENT
    #     accmode = os.O_RDONLY | os.O_WRONLY | os.O_RDWR
    #     if (flags & accmode) != os.O_RDONLY:
    #         print "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
    #         return -errno.EACCES

    # def read(self, path, size, offset):
    #     print "=======================read======================="
    #     fname=os.path.basename(path)
    #     print "fname",fname
    #     buf = haokan.getImage(fname)
    #     print "buf length",len(buf)
    #     return buf
    class HaokanFile(object):
        def __init__(self, path, flags, *mode):
            print "=============================HaokanFile",path
            fname=os.path.basename(path)
            local_file=haokan.getImage(fname)
            self.file = os.fdopen(os.open(local_file, flags, *mode),
                                  flag2mode(flags))
            self.fd = self.file.fileno()
        def read(self, length, offset):
            print "========================read HaokanFile",length
            self.file.seek(offset)
            return self.file.read(length)
        def release(self, flags):
            self.file.close()
        def _fflush(self):
            if 'w' in self.file.mode or 'a' in self.file.mode:
                self.file.flush()
        def fsync(self, isfsyncfile):
            self._fflush()
            if isfsyncfile and hasattr(os, 'fdatasync'):
                os.fdatasync(self.fd)
            else:
                os.fsync(self.fd)
        def flush(self):
            self._fflush()
            # cf. xmp_flush() in fusexmp_fh.c
            os.close(os.dup(self.fd))
        def fgetattr(self):
            return os.fstat(self.fd)
        def ftruncate(self, len):
            self.file.truncate(len)
        def lock(self, cmd, owner, **kw):
            op = { fcntl.F_UNLCK : fcntl.LOCK_UN,
                   fcntl.F_RDLCK : fcntl.LOCK_SH,
                   fcntl.F_WRLCK : fcntl.LOCK_EX }[kw['l_type']]
            if cmd == fcntl.F_GETLK:
                return -EOPNOTSUPP
            elif cmd == fcntl.F_SETLK:
                if op != fcntl.LOCK_UN:
                    op |= fcntl.LOCK_NB
            elif cmd == fcntl.F_SETLKW:
                pass
            else:
                return -EINVAL
            fcntl.lockf(self.fd, op, kw['l_start'], kw['l_len'])

    def main(self, *a, **kw):
        self.file_class = self.HaokanFile
        return Fuse.main(self, *a, **kw)

def main():
    usage="""
Userspace Haokanbu FileSystem.
http://www.haokanbu.com/

""" + Fuse.fusage
    server = HaokanFS(version="%prog " + fuse.__version__,
                     usage=usage,
                     dash_s_do='setsingle')

    server.parse(errex=1)
    server.main()

if __name__ == '__main__':
    main()
